home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gdevwdib.c < prev    next >
C/C++ Source or Header  |  1997-05-09  |  19KB  |  675 lines

  1. /* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevwdib.c */
  20. /* MS Windows 3.n driver for Ghostscript using a DIB for buffering. */
  21. #include "gdevmswn.h"
  22. #include "gxdevmem.h"
  23. #include "gsdll.h"
  24.  
  25. #ifdef __WIN32__
  26. #  define USE_SEGMENTS 0
  27. #else
  28. #  define USE_SEGMENTS 1
  29. #endif
  30.  
  31. /* Make sure we cast to the correct structure type. */
  32. typedef struct gx_device_win_dib_s gx_device_win_dib;
  33. #undef wdev
  34. #define wdev ((gx_device_win_dib *)dev)
  35.  
  36. /* Device procedures */
  37.  
  38. /* See gxdevice.h for the definitions of the procedures. */
  39. private dev_proc_open_device(win_dib_open);
  40. private dev_proc_get_initial_matrix(win_dib_get_initial_matrix);
  41. private dev_proc_close_device(win_dib_close);
  42. private dev_proc_fill_rectangle(win_dib_fill_rectangle);
  43. private dev_proc_copy_mono(win_dib_copy_mono);
  44. private dev_proc_copy_color(win_dib_copy_color);
  45. private dev_proc_get_bits(win_dib_get_bits);
  46. private dev_proc_put_params(win_dib_put_params);
  47. /* Windows-specific procedures */
  48. private win_proc_repaint(win_dib_repaint);
  49. private win_proc_alloc_bitmap(win_dib_alloc_bitmap);
  50. private win_proc_free_bitmap(win_dib_free_bitmap);
  51.  
  52. /* The device descriptor */
  53. struct gx_device_win_dib_s {
  54.     gx_device_common;
  55.     gx_device_win_common;
  56.  
  57. #if USE_SEGMENTS
  58.     /* The following help manage the division of the DIB */
  59.     /* into 64K segments.  Each block of y_block scan lines */
  60.     /* starting at y_base mod 64K falls in a single segment. */
  61.     /* Since the raster is a power of 2, y_block is a power of 2. */
  62.  
  63.     int y_block;
  64.     int y_base;
  65.     int y_mask;        /* y_block - 1 */
  66. #endif        /* USE_SEGMENTS */
  67.  
  68.     HGLOBAL hmdata;
  69. #ifdef __WIN32__
  70.     HANDLE hmtx;
  71. #endif
  72.     int lock_count;
  73.     gx_device_memory mdev;
  74. };
  75. private gx_device_procs win_dib_procs = {
  76.     win_dib_open,
  77.     win_dib_get_initial_matrix,
  78.     win_sync_output,
  79.     win_output_page,
  80.     win_dib_close,
  81.     win_map_rgb_color,
  82.     win_map_color_rgb,
  83.     win_dib_fill_rectangle,
  84.     NULL,            /* tile_rectangle */
  85.     win_dib_copy_mono,
  86.     win_dib_copy_color,
  87.     NULL,            /* draw_line */
  88.     win_dib_get_bits /* NULL */,            /* get_bits */
  89.     win_get_params,
  90.     win_dib_put_params,
  91.     NULL,            /* map_cmyk_color */
  92.     win_get_xfont_procs,
  93.     NULL,            /* get_xfont_device */
  94.     NULL,            /* map_rgb_alpha_color */
  95.     gx_page_device_get_page_device,
  96.     win_get_alpha_bits
  97. };
  98. gx_device_win_dib far_data gs_mswindll_device = {
  99.     std_device_std_body(gx_device_win_dib, &win_dib_procs, "mswindll",
  100.       INITIAL_WIDTH, INITIAL_HEIGHT,     /* win_open() fills these in later */
  101.       INITIAL_RESOLUTION, INITIAL_RESOLUTION    /* win_open() fills these in later */
  102.     ),
  103.      { 0 },                /* std_procs */
  104.     0,                /* BitsPerPixel */
  105.     2,                /* nColors */
  106.     1,                /* Text Alpha bits */
  107.     1,                /* Graphics Alpha bits */
  108.     0,                /* mapped_color_flags */
  109.     win_dib_alloc_bitmap,
  110.     win_dib_free_bitmap
  111. };
  112.  
  113. /* forward declarations */
  114. private HGLOBAL win_dib_make_dib(gx_device_win *dev, int orgx, int orgy, int wx, int wy);
  115. private int win_dib_lock_device(unsigned char *device, int flag);
  116.  
  117.  
  118. /* Open the win_dib driver */
  119. private int
  120. win_dib_open(gx_device *dev)
  121. {
  122.     int code = win_open(dev);
  123.     if ( code < 0 ) return code;
  124.  
  125. #ifdef __WIN32__
  126.     if (!is_win32s)
  127.         wdev->hmtx = CreateMutex(NULL, FALSE, NULL); /* unnamed mutex, initially unowned */
  128. #endif
  129.     if ( gdev_mem_device_for_bits(dev->color_info.depth) == 0 )
  130.     {    win_close(dev);
  131.         return gs_error_rangecheck;
  132.     }
  133.     code = win_dib_alloc_bitmap((gx_device_win *)dev, dev);
  134.     if ( code < 0 ) {
  135.          win_close(dev);
  136.          return code;
  137.     }
  138.     /* notify caller about new device */
  139.     (*pgsdll_callback)(GSDLL_DEVICE, (unsigned char *)dev, 1);
  140.     (*pgsdll_callback)(GSDLL_SIZE, (unsigned char *)dev,
  141.              (dev->width & 0xffff) +
  142.              ((ulong)(dev->height & 0xffff) << 16));
  143.     return code;
  144. }
  145.  
  146. /* Get the initial matrix.  DIBs, unlike most displays, */
  147. /* put (0,0) in the lower left corner. */
  148. private void
  149. win_dib_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
  150. {    pmat->xx = dev->x_pixels_per_inch / 72.0;
  151.     pmat->xy = 0.0;
  152.     pmat->yx = 0.0;
  153.     pmat->yy = dev->y_pixels_per_inch / 72.0;
  154.     pmat->tx = 0.0;
  155.     pmat->ty = 0.0;
  156. }
  157.  
  158. /* Close the win_dib driver */
  159. private int
  160. win_dib_close(gx_device *dev)
  161. {int code;
  162.     /* wait until bitmap is not being used by caller */
  163.         win_dib_lock_device((unsigned char *)dev, 1);
  164.     (*pgsdll_callback)(GSDLL_DEVICE, (unsigned char *)dev, 0);
  165.         win_dib_lock_device((unsigned char *)dev, 0);
  166.     win_dib_free_bitmap((gx_device_win *)dev);
  167. #ifdef __WIN32__
  168.     if (!is_win32s)
  169.         CloseHandle(wdev->hmtx);
  170. #endif
  171.     code = win_close(dev);
  172.     return code;
  173. }
  174.  
  175. #define wmdev ((gx_device *)&wdev->mdev)
  176. #define wmproc(proc) (*dev_proc(&wdev->mdev, proc))
  177.  
  178. #if USE_SEGMENTS
  179.  
  180. /* The drawing routines must all be careful not to cross */
  181. /* a segment boundary. */
  182.  
  183. #define single_block(y, h)\
  184.   !(((y - wdev->y_base) ^ (y - wdev->y_base + h - 1)) & ~wdev->y_mask)
  185.  
  186. #define BEGIN_BLOCKS\
  187. {    int by, bh, left = h;\
  188.     for ( by = y; left > 0; by += bh, left -= bh )\
  189.     {    bh = wdev->y_block - (by & wdev->y_mask);\
  190.         if ( bh > left ) bh = left;
  191. #define END_BLOCKS\
  192.     }\
  193. }
  194.  
  195. #endif        /* (!)USE_SEGMENTS */
  196.  
  197. /* Fill a rectangle. */
  198. private int
  199. win_dib_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  200.   gx_color_index color)
  201. {
  202. #if USE_SEGMENTS
  203.     if ( single_block(y, h) )
  204.     {    wmproc(fill_rectangle)(wmdev, x, y, w, h, color);
  205.     }
  206.     else
  207.     {    /* Divide the transfer into blocks. */
  208.         BEGIN_BLOCKS
  209.             wmproc(fill_rectangle)(wmdev, x, by, w, bh, color);
  210.         END_BLOCKS
  211.     }
  212. #else
  213.     wmproc(fill_rectangle)(wmdev, x, y, w, h, color);
  214. #endif
  215.     return 0;
  216. }
  217.  
  218. /* Copy a monochrome bitmap.  The colors are given explicitly. */
  219. /* Color = gx_no_color_index means transparent (no effect on the image). */
  220. private int
  221. win_dib_copy_mono(gx_device *dev,
  222.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  223.   int x, int y, int w, int h,
  224.   gx_color_index zero, gx_color_index one)
  225. {
  226. #if USE_SEGMENTS
  227.     if ( single_block(y, h) )
  228.     {    wmproc(copy_mono)(wmdev, base, sourcex, raster, id,
  229.                      x, y, w, h, zero, one);
  230.     }
  231.     else
  232.     {    /* Divide the transfer into blocks. */
  233.         const byte *source = base;
  234.         BEGIN_BLOCKS
  235.             wmproc(copy_mono)(wmdev, source, sourcex, raster,
  236.                       gx_no_bitmap_id, x, by, w, bh,
  237.                       zero, one);
  238.             source += bh * raster;
  239.         END_BLOCKS
  240.     }
  241. #else
  242.     wmproc(copy_mono)(wmdev, base, sourcex, raster, id,
  243.               x, y, w, h, zero, one);
  244. #endif
  245.     return 0;
  246. }
  247.  
  248. /* Copy a color pixel map.  This is just like a bitmap, except that */
  249. /* each pixel takes 8 or 4 bits instead of 1 when device driver has color. */
  250. private int
  251. win_dib_copy_color(gx_device *dev,
  252.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  253.   int x, int y, int w, int h)
  254. {
  255. #if USE_SEGMENTS
  256.     if ( single_block(y, h) )
  257.     {    wmproc(copy_color)(wmdev, base, sourcex, raster, id,
  258.                    x, y, w, h);
  259.     }
  260.     else
  261.     {    /* Divide the transfer into blocks. */
  262.         const byte *source = base;
  263.         BEGIN_BLOCKS
  264.             wmproc(copy_color)(wmdev, source, sourcex, raster,
  265.                        gx_no_bitmap_id, x, by, w, bh);
  266.             source += by * raster;
  267.         END_BLOCKS
  268.     }
  269. #else
  270.     wmproc(copy_color)(wmdev, base, sourcex, raster, id,
  271.                x, y, w, h);
  272. #endif
  273.     return 0;
  274. }
  275.  
  276. int
  277. win_dib_get_bits(gx_device *dev, int y, byte *str, byte **actual_data)
  278. {
  279.     return wmproc(get_bits)(wmdev, y, str, actual_data);
  280. }
  281.  
  282. int
  283. win_dib_put_params(gx_device *dev, gs_param_list *plist)
  284. {
  285. int code;
  286.     win_dib_lock_device((unsigned char *)dev, 1);
  287.     code = win_put_params(dev, plist);
  288.     win_dib_lock_device((unsigned char *)dev, 0);
  289.     return code;
  290. }
  291.  
  292. /* ------ DLL device procedures ------ */
  293.  
  294. /* make a copy of the device bitmap and return shared memory handle to it */
  295. /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
  296. HGLOBAL GSDLLAPI
  297. gsdll_copy_dib(unsigned char *device)
  298. {
  299. gx_device_win_dib *dev = (gx_device_win_dib *)device;
  300.     if (!dev || !dev->is_open || dev->mdev.width==0 || dev->mdev.height==0)
  301.         return (HGLOBAL)NULL;
  302.     return win_dib_make_dib((gx_device_win *)dev, 0, 0, dev->width, dev->height);
  303. }
  304.  
  305. /* make a copy of the device palette and return a handle to it */
  306. /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
  307. HPALETTE GSDLLAPI
  308. gsdll_copy_palette(unsigned char *device)
  309. {
  310. gx_device_win_dib *dev = (gx_device_win_dib *)device;
  311.     if (!dev || !dev->is_open || dev->mdev.width==0 || dev->mdev.height==0)
  312.         return (HPALETTE)NULL;
  313.     if (wdev->nColors > 0)
  314.         return CreatePalette(dev->limgpalette);
  315.     return (HPALETTE)NULL;
  316. }
  317.  
  318. /* copy the rectangle src from the device bitmap */
  319. /* to the rectangle dest on the device given by hdc */
  320. /* hdc must be a device context for a device (NOT a bitmap) */
  321. /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
  322. void GSDLLAPI
  323. gsdll_draw(unsigned char *device, HDC hdc, LPRECT dest, LPRECT src)
  324. {
  325. gx_device_win_dib *dev = (gx_device_win_dib *)device;
  326. HPALETTE oldpalette;
  327.     if (!dev || !dev->is_open || dev->mdev.width==0 || dev->mdev.height==0)
  328.         return;
  329.     if (dev->nColors > 0) {
  330.         oldpalette = SelectPalette(hdc,dev->himgpalette,FALSE);
  331.         RealizePalette(hdc);
  332.     }
  333.     win_dib_repaint((gx_device_win *)dev, hdc, dest->left, dest->top,
  334.         dest->right-dest->left, dest->bottom-dest->top,  
  335.         src->left, src->top);
  336.     if (dev->nColors > 0) {
  337.         SelectPalette(hdc,oldpalette,FALSE);
  338.     }
  339.     return;
  340. }
  341.  
  342. /* ------ Windows-specific device procedures ------ */
  343.  
  344.  
  345. /* Repaint a section of the window. */
  346. private void
  347. win_dib_repaint(gx_device_win *dev, HDC hdc, int dx, int dy, int wx, int wy,
  348.   int sx, int sy)
  349. {    struct bmi_s {
  350.       BITMAPINFOHEADER h;
  351.       ushort pal_index[256];
  352.     } bmi;
  353.     int i;
  354.     UINT which_colors;
  355.  
  356.     bmi.h.biSize = sizeof(bmi.h);
  357.     bmi.h.biWidth = wdev->mdev.width;
  358.     bmi.h.biHeight = wy;
  359.     bmi.h.biPlanes = 1;
  360.     bmi.h.biBitCount = dev->color_info.depth;
  361.     bmi.h.biCompression = 0;
  362.     bmi.h.biSizeImage = 0;            /* default */
  363.     bmi.h.biXPelsPerMeter = 0;        /* default */
  364.     bmi.h.biYPelsPerMeter = 0;        /* default */
  365.     if ( dev->BitsPerPixel <= 8 )
  366.       {    bmi.h.biClrUsed = wdev->nColors;
  367.         bmi.h.biClrImportant = wdev->nColors;
  368.         for ( i = 0; i < wdev->nColors; i++ )
  369.           bmi.pal_index[i] = i;
  370.         which_colors = DIB_PAL_COLORS;
  371.       }
  372.     else
  373.       {    bmi.h.biClrUsed = 0;
  374.         bmi.h.biClrImportant = 0;
  375.         which_colors = DIB_RGB_COLORS;
  376.       }
  377.     /*
  378.      * Windows apparently limits the size of a single transfer
  379.      * to 2 Mb, which can be exceeded on 24-bit displays.
  380.      * Deal with this here.
  381.      */
  382. #define max_transfer 2000000
  383.     if ( wdev->mdev.raster > 0 )        /* just in case! */
  384.     {    long ny = max_transfer / wdev->mdev.raster;
  385.         for ( ; wy > ny; dy += ny, wy -= ny, sy += ny )
  386.           SetDIBitsToDevice(hdc, dx, dy, wx, ny,
  387.             sx, 0, 0, ny,
  388.             wdev->mdev.line_ptrs[wdev->height - (sy + ny)],
  389.             (BITMAPINFO FAR *)&bmi, which_colors);
  390.     }
  391. #undef max_transfer
  392.     SetDIBitsToDevice(hdc, dx, dy, wx, wy,
  393.               sx, 0, 0, wy,
  394.               wdev->mdev.line_ptrs[wdev->height - (sy + wy)],
  395.               (BITMAPINFO FAR *)&bmi, which_colors);
  396. }
  397.  
  398. /* This makes a DIB that contains all or part of the bitmap. */
  399. /* The bitmap pixel orgx must start on a byte boundary. */
  400. private HGLOBAL
  401. win_dib_make_dib(gx_device_win *dev, int orgx, int orgy, int wx, int wy)
  402. {
  403. #define xwdev ((gx_device_win_dib *)dev)
  404.     gx_color_value prgb[3];
  405.     HGLOBAL hglobal;
  406.     BYTE FAR *pDIB;
  407.     BITMAPINFOHEADER FAR *pbmih;
  408.     RGBQUAD FAR *pColors;
  409.     BYTE huge *pBits;
  410.     BYTE huge *pLine;
  411.     ulong bitmapsize;
  412.     int palcount;
  413.     int i;
  414.     UINT lwidth;        /* line width in bytes rounded up to multiple of 4 bytes */
  415. #ifdef USE_SEGMENTS
  416.     int loffset;         /* byte offset to start of line */
  417.     UINT lseg;        /* bytes remaining in this segment */
  418. #endif
  419.  
  420.     if (orgx + wx > wdev->width)
  421.         wx = wdev->width - orgx;
  422.     if (orgy + wy > wdev->height)
  423.         wy = wdev->height - orgy;
  424.  
  425.     loffset = orgx * wdev->color_info.depth / 8;
  426.     lwidth =  ((wx * wdev->color_info.depth + 31) & ~31) >> 3;
  427.     bitmapsize = (long)lwidth * wy;
  428.  
  429.     if (wdev->color_info.depth == 24)
  430.         palcount = 0;
  431.     else
  432.         palcount = wdev->nColors;
  433.  
  434.     hglobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(BITMAPINFOHEADER) 
  435.         + sizeof(RGBQUAD) * palcount + bitmapsize);
  436.     if (hglobal == (HGLOBAL)NULL) {
  437.         MessageBeep(-1);
  438.         return(HGLOBAL)NULL;
  439.     }
  440.     pDIB = (BYTE FAR *)GlobalLock(hglobal);
  441.     if (pDIB == (BYTE FAR *)NULL) {
  442.         MessageBeep(-1);
  443.         return(HGLOBAL)NULL;
  444.     }
  445.     pbmih = (BITMAPINFOHEADER FAR *)(pDIB); 
  446.     pColors = (RGBQUAD FAR *)(pDIB + sizeof(BITMAPINFOHEADER));
  447.     pBits = (BYTE huge *)(pDIB + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * palcount);
  448.  
  449.     pbmih->biSize = sizeof(BITMAPINFOHEADER);
  450.     pbmih->biWidth = wx;
  451.     pbmih->biHeight = wy;
  452.     pbmih->biPlanes = 1;
  453.     pbmih->biBitCount = wdev->color_info.depth;
  454.     pbmih->biCompression = 0;
  455.     pbmih->biSizeImage = 0;            /* default */
  456.     pbmih->biXPelsPerMeter = (DWORD)(dev->x_pixels_per_inch / 25.4 * 1000);
  457.     pbmih->biYPelsPerMeter = (DWORD)(dev->y_pixels_per_inch / 25.4 * 1000);
  458.     pbmih->biClrUsed = palcount;
  459.     pbmih->biClrImportant = palcount;
  460.     for ( i = 0; i < palcount; i++ ) {
  461.         win_map_color_rgb((gx_device *)wdev, (gx_color_index)i, prgb);
  462.         pColors[i].rgbRed   = win_color_value(prgb[0]);
  463.         pColors[i].rgbGreen = win_color_value(prgb[1]);
  464.         pColors[i].rgbBlue  = win_color_value(prgb[2]);
  465.         pColors[i].rgbReserved = 0;
  466.     }
  467.  
  468.     pLine = pBits;
  469.     for ( i = orgy; i < orgy + wy; i++ ) {
  470. #if USE_SEGMENTS
  471.         /* Window 3.1 has hmemcpy, but 3.0 doesn't */
  472.         lseg = (UINT)(-OFFSETOF(pLine));   /* remaining bytes in this segment */
  473.         if (lseg >= lwidth) { 
  474.            _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lwidth);
  475.         }
  476.         else { /* break up transfer to avoid crossing segment boundary */
  477.            _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lseg);
  478.            _fmemcpy(pLine+lseg, xwdev->mdev.line_ptrs[i] + loffset + lseg, lwidth - lseg);
  479.         }
  480. #else
  481.         memcpy(pLine, xwdev->mdev.line_ptrs[i], lwidth);
  482. #endif
  483.         pLine += lwidth;
  484.     }
  485.  
  486.     GlobalUnlock(hglobal);
  487.     return hglobal;
  488. }
  489.  
  490.  
  491. /* Allocate the backing bitmap. */
  492. private int
  493. win_dib_alloc_bitmap(gx_device_win *dev, gx_device *param_dev)
  494. {
  495.     int width;
  496.     gx_device_memory mdev;
  497.     HGLOBAL hmdata;
  498.     byte huge *base;
  499.     byte huge *ptr_base;
  500.     uint ptr_size;
  501.     uint raster;
  502. #ifdef USE_SEGMENTS
  503.     ulong data_size;
  504. #endif
  505.  
  506. #ifdef __WIN32__
  507.     if (is_win32s) {
  508. #endif
  509.       /* Round up the width so that the scan line size is a power of 2. */
  510.         if (dev->color_info.depth == 24) {
  511.         width = param_dev->width * 3 - 1;
  512.         while ( width & (width + 1) ) width |= width >> 1;
  513.         width = (width + 1) / 3;
  514.         }
  515.         else {
  516.         width = param_dev->width - 1;
  517.         while ( width & (width + 1) ) width |= width >> 1;
  518.         width++;
  519.         }
  520. #ifdef __WIN32__
  521.     }
  522.     else {    /* don't have to worry about segments so use less memory */
  523.         width = param_dev->width;
  524.     }
  525. #endif
  526.  
  527.     /* Finish initializing the DIB. */
  528.  
  529.     gs_make_mem_device(&mdev, gdev_mem_device_for_bits(dev->color_info.depth), 0, 0, (gx_device *)dev);
  530.     mdev.width = width;
  531.     mdev.height = param_dev->height;
  532.     raster = gdev_mem_raster(&mdev);
  533.     data_size = (ulong)raster * mdev.height;
  534.     ptr_size = sizeof(byte **) * mdev.height;
  535.     hmdata = GlobalAlloc(0, raster + data_size + ptr_size * 2);
  536.     if ( hmdata == 0 ) {
  537.         return win_nomemory();
  538.     }
  539.  
  540.     /* Nothing can go wrong now.... */
  541.  
  542.     wdev->hmdata = hmdata;
  543.     base = GlobalLock(hmdata);
  544. #if USE_SEGMENTS
  545.     /* Adjust base so scan lines, and the pointer table, */
  546.     /* don't cross a segment boundary. */
  547.     base += (-PTR_OFF(base) & (raster - 1));
  548.     ptr_base = base + data_size;
  549.     if ( PTR_OFF(ptr_base + ptr_size) < ptr_size )
  550.         base += (uint)-PTR_OFF(ptr_base);
  551.     wdev->y_block = 0x10000L / raster;
  552.     wdev->y_mask = wdev->y_block - 1;
  553.     if ( (wdev->y_base = PTR_OFF(base)) != 0 )
  554.         wdev->y_base = -(PTR_OFF(base) / raster);
  555. #endif
  556.     wdev->mdev = mdev;
  557.     wdev->mdev.base = (byte *)base;
  558.     wmproc(open_device)((gx_device *)&wdev->mdev);
  559.  
  560.     if (wdev->is_open)
  561.       (*pgsdll_callback)(GSDLL_SIZE, (unsigned char *)dev,
  562.                  (dev->width & 0xffff) +
  563.                  ((ulong)(dev->height & 0xffff) << 16));
  564.  
  565.     return 0;
  566. }
  567.  
  568.  
  569. /* Free the backing bitmap. */
  570. private void
  571. win_dib_free_bitmap(gx_device_win *dev)
  572. {    HGLOBAL hmdata = wdev->hmdata;
  573.     GlobalUnlock(hmdata);
  574.     GlobalFree(hmdata);
  575. }
  576.  
  577. /* Lock the device (so it's size cannot be changed) if flag = TRUE */
  578. /* or unlock the device if flag = FALSE */
  579. /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
  580. private int
  581. win_dib_lock_device(unsigned char *device, int flag)
  582. {
  583. gx_device *dev = (gx_device *)device;
  584. #ifdef __WIN32__
  585.     if (!is_win32s) {
  586.     if (flag) {
  587.         if (WaitForSingleObject(wdev->hmtx, 60000) == WAIT_TIMEOUT)
  588.         return 2;
  589.         return 1;
  590.     }
  591.     ReleaseMutex(wdev->hmtx);
  592.     return 0;
  593.     }
  594. #endif
  595.     if (flag)
  596.     wdev->lock_count++;
  597.     else 
  598.     wdev->lock_count--;
  599.     if (wdev->lock_count < 0)
  600.     wdev->lock_count = 0;
  601.     return wdev->lock_count;
  602. }
  603.  
  604. int GSDLLAPI _export
  605. gsdll_lock_device(unsigned char *device, int flag)
  606. {
  607.     return win_dib_lock_device(device, flag);
  608. }
  609.  
  610.  
  611. /* Copy bitmap
  612.  * If pbmih nonzero, copy the BITMAPINFOHEADER.
  613.  * If prgbquad nonzero, copy the palette.
  614.  *   number of entries copied is given by pbmih->biClrUsed
  615.  * If ppbyte nonzero, return pointer to row.
  616.  *   pointer is only valid while device is locked
  617.  * GS can change the palette while the device is locked.
  618.  * Do not call this function while GS is busy.
  619.  * If all pbmih and prgbquad and ppbyte are all NULL,
  620.  * return value is byte count needed for BITMAPINFOHEADER
  621.  * and palette and one bitmap row.
  622.  * Otherwise return value is 0;
  623.  *
  624.  * This function exists to allow the bitmap to be copied to a file
  625.  * or structured storage, without the overhead of having two copies
  626.  * of the bitmap in memory at the same time.
  627.  */
  628. int GSDLLAPI _export
  629. gsdll_get_bitmap_row(unsigned char *device, LPBITMAPINFOHEADER pbmih,
  630.     LPRGBQUAD prgbquad, LPBYTE *ppbyte, unsigned int row)
  631. {
  632.     int palcount;
  633.     gx_device_win_dib *dev = (gx_device_win_dib *)device;
  634.     palcount = (dev->color_info.depth == 24) ? 0 : dev->nColors;
  635.  
  636.     if (pbmih) {
  637.     pbmih->biSize = sizeof(BITMAPINFOHEADER);
  638.     pbmih->biWidth = dev->width;
  639.     pbmih->biHeight = dev->mdev.height;
  640.     pbmih->biPlanes = 1;
  641.     pbmih->biBitCount = dev->color_info.depth;
  642.     pbmih->biCompression = 0;
  643.     pbmih->biSizeImage = 0;            /* default */
  644.     pbmih->biXPelsPerMeter = (DWORD)(dev->x_pixels_per_inch / 25.4 * 1000);
  645.     pbmih->biYPelsPerMeter = (DWORD)(dev->y_pixels_per_inch / 25.4 * 1000);
  646.     pbmih->biClrUsed = palcount;
  647.     pbmih->biClrImportant = palcount;
  648.     }
  649.  
  650.     if (prgbquad) {
  651.     int i;
  652.         gx_color_value prgb[3];
  653.     for ( i = 0; i < palcount; i++ ) {
  654.         win_map_color_rgb((gx_device *)wdev, (gx_color_index)i, prgb);
  655.         prgbquad[i].rgbRed   = win_color_value(prgb[0]);
  656.         prgbquad[i].rgbGreen = win_color_value(prgb[1]);
  657.         prgbquad[i].rgbBlue  = win_color_value(prgb[2]);
  658.         prgbquad[i].rgbReserved = 0;
  659.     }
  660.     }
  661.  
  662.     if (ppbyte) {
  663.     if (row < dev->mdev.height)
  664.         *ppbyte = dev->mdev.line_ptrs[row];
  665.     else
  666.         *ppbyte = NULL;
  667.     }
  668.  
  669.     if ((pbmih == NULL) && (prgbquad == NULL) && (ppbyte == NULL))
  670.     return sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)
  671.         + gdev_mem_raster(&(dev->mdev));
  672.     return 0;
  673. }
  674.  
  675.